package com.bazaaroid.server.gae.core.persistence.query;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("serial")
public class JDOQuery implements Serializable {

	private String type;
	private String className;
	private List<QueryFilter> queryFilters;
	private List<Serializable> paramValues;
	private String ordering;
	
	static class QueryFilter implements Serializable {
		private String fieldName;
		private String operator;
		private String paramName;
		private String paramType;
		private String logicalSeparator;
		
		public QueryFilter() { }

		public QueryFilter(String fn, String op, String pn, String pt,
				String ls) {
			fieldName = fn;
			operator = op;
			paramName = pn;
			paramType = pt;
			logicalSeparator = ls;
		}
	}

	// Builder methods to build a complete query
	public static JDOQuery selectFrom(String className) {
		return new JDOQuery(JDOQueryConstants.SELECT, className);
	}

	public static JDOQuery deleteFrom(String className) {
		return new JDOQuery(JDOQueryConstants.DELETE, className);
	}

	public JDOQuery where(String classField, String operator, String fieldType, String value) {
		addFilter(classField, operator, classField + "Param", fieldType, value);
		return this;
	}

	public JDOQuery and() {
		addLogicalOperator(JDOQueryConstants.AND);
		return this;
	}

	public JDOQuery or() {
		addLogicalOperator(JDOQueryConstants.OR);
		return this;
	}

	public JDOQuery orderBy(String field, String order) {
		addOrdering(field, order);
		return this;
	}

	// End builder methods
	protected JDOQuery(){
		queryFilters = new ArrayList<QueryFilter>();
	}

	protected JDOQuery(String cl) {
		this();
		className = cl;
		type = JDOQueryConstants.SELECT;
	}

	protected JDOQuery(String type, String cl) {
		this(type);
		className = cl;
	}

	public List<Serializable> getParamValues() {
		return paramValues;
	}
	
	protected void addFilter(String fieldName, String operator,
			String paramName, String paramType, String paramValue) {
		addFilter(fieldName, operator, paramName, paramType, paramValue, null);
	}

	protected void addFilter(String fieldName, String operator,
			String paramName, String paramType, String paramValue,
			String logical) {
		addFilter(new QueryFilter(fieldName, operator, paramName,
				paramType, logical));

		if (paramValues == null)
			paramValues = new ArrayList<Serializable>();
		paramValues.add(paramValue);
	}

	private void addFilter(QueryFilter filter) {
		queryFilters.add(filter);
	}

	private void addLogicalOperator(String logical) {
		QueryFilter lastFilter = queryFilters.get(queryFilters.size() - 1);
		lastFilter.logicalSeparator = logical;
	}

	private void addOrdering(String field, String order) {
		ordering = field + ' ' + order;		
	}

	@Override
	public String toString() {

		StringBuffer buffer = new StringBuffer();

		buffer.append(type);
		buffer.append(className);

		if (queryFilters.size() > 0) {

			buffer.append(" where ");

			// Add filters
			for (QueryFilter filter : queryFilters) {

				buffer.append(filter.fieldName);
				buffer.append(filter.operator);
				buffer.append(filter.paramName);

				if (filter.logicalSeparator != null)
					buffer.append(filter.logicalSeparator);
			}

			buffer.append(" parameters ");

			// Add param declarations
			boolean addComma = false;
			for (QueryFilter filter : queryFilters) {

				if (addComma)
					buffer.append(", ");
				buffer.append(filter.paramType);
				buffer.append(" ");
				buffer.append(filter.paramName);
				addComma = true;
			}
		}

		// Add ordering
		if (ordering != null) {
			buffer.append(" order by ");
			buffer.append(ordering);
		}

		return buffer.toString();
	}
}

